﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "PickFilterDlg.h"
#include "ICategoryLibrary.h"
#include "ICategory.h"
#include "IMainWindow.h"
#include "IDocument.h"
#include "IUiDocument.h"
#include "IElementCanBePickedInModifyAction.h"
#include "IDock.h"
#include "IDockManager.h"
#include "IUiDocumentViewManager.h"
#include "PickFilterDialogEventHandlers.h"
#include "GbmpElementCanBePickedByCategoryInModifyAction.h"
#include "qevent.h"
#include "IUiManager.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

static bool m_isFamilyDoc = true;

PickFilterDlg::PickFilterDlg(gcmp::IDocument* pDoc, QWidget *parent)
    : QDialog(parent)
    , m_pDoc(pDoc)
{
    m_ui.setupUi(this);
    InitQTree();
    QMetaObject::connectSlotsByName(this);
    // 消息处理。
    connect(m_ui.treeWidget, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(OnTreeItemClicked(QTreeWidgetItem*, int)));

    // 初始化事件处理
    m_opUiDocEventHandler = NEW_AS_OWNER_PTR(PickFilterDialogUiDocumentEventHandler);
    m_opUiViewEventHandler = NEW_AS_OWNER_PTR(PickFilterDialogUiViewEventHandler);
}

PickFilterDlg::~PickFilterDlg(void)
{
}

QSize PickFilterDlg::sizeHint() const
{
    return QSize(200, 500); 
}

void PickFilterDlg::InitQTree()
{
    // 创建或者获取ModifyAction中Element拾取过滤
    const IElementCanBePickedInModifyAction * pElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    if (nullptr == pElementCanBePickedInModifyAction)
    {
        OwnerPtr<GbmpElementCanBePickedByCategoryInModifyAction> opElementCanBePickedByCategoryInModifyAction = NEW_AS_OWNER_PTR(GbmpElementCanBePickedByCategoryInModifyAction);
        opElementCanBePickedByCategoryInModifyAction->InitCategories(m_categoryIds);
        IElementCanBePickedInModifyAction::Set(TransferOwnership(opElementCanBePickedByCategoryInModifyAction));
        pElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementCanBePickedInModifyAction, L"IElementCanBePickedInModifyAction为空?",L"GDMPLab",L"2024-03-30");

    m_ui.treeWidget->clear();

    const bool sortingEnabled = m_ui.treeWidget->isSortingEnabled();
    m_ui.treeWidget->setSortingEnabled(false);

    QTreeWidgetItem *topLevelItem = NEW_AS_QT(QTreeWidgetItem, m_ui.treeWidget);
    topLevelItem->setCheckState(0, Qt::Checked);
    topLevelItem->setText(0, QString::fromStdWString(GBMP_TR(L"所有对象")));

    FOR_EACH(curId, m_categoryIds)
    {
        const ICategory * pCurCategory = ICategoryLibrary::Get(m_pDoc)->GetCategory(curId);
        DBG_WARN_AND_CONTINUE_UNLESS(pCurCategory, L"获取到的ICategory指针为空，不合法",L"GDMPLab",L"2024-03-30");

        QTreeWidgetItem *curItem = NEW_AS_QT(QTreeWidgetItem, topLevelItem);
        curItem->setCheckState(0, Qt::Checked);
        curItem->setText(0, QString::fromStdWString(GBMP_TR(pCurCategory->GetName())));
        topLevelItem->addChild(curItem);
    }

    m_ui.treeWidget->setSortingEnabled(sortingEnabled);
    m_ui.treeWidget->expandAll();
}

void PickFilterDlg::SetCategoryIds(const std::vector<gcmp::UniIdentity>& categoryIds)
{
    m_categoryIds = categoryIds;
    InitQTree();
}

IDockablePickFilterWidget * gcmp::PickFilterDlg::Get()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager * pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空",L"GDMPLab",L"2024-03-30");
    IDock* pDock = pDockManager->GetDock(PickFilterDlg::GetDockName());
    if (!pDock)
    {
        return nullptr;
    }
    IWidget * pWidget = pDock->GetWidget();
    return dynamic_cast<IDockablePickFilterWidget*>(pWidget);
}

IDockablePickFilterWidget * gcmp::PickFilterDlg::Create(const IPickFilterWidgetInitializer & initializer)
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");

    IDockManager * pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空",L"GDMPLab",L"2024-03-30");

    IUiDocumentViewManager * pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDocViewMgr, L"pUiDocViewMgr为空",L"GDMPLab",L"2024-03-30");

    IUiDocument * pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiDoc, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");

    IDocument * pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IDock> opDock = pDockManager->CreateDock(PickFilterDlg::GetDockName(), GBMP_TR(L"拾取过滤"));

    OwnerPtr<PickFilterDlg> opPickDlg = NEW_AS_OWNER_PTR(PickFilterDlg, pDoc);
    IDockablePickFilterWidget * pPickFilterDlg = opPickDlg.get();
    opPickDlg->setMinimumWidth(200);
    opPickDlg->SetCategoryIds(initializer.GetCategories(pDoc));
    opDock->SetWidget(TransferOwnership(opPickDlg));

    pDockManager->AddDock(TransferOwnership(opDock), DockArea::Right, DockOrientation::Vertical);

    return pPickFilterDlg;
}

void PickFilterDlg::UpdateQTree(IUiDocument* pUIDoc)
{
    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"doc为空",L"GDMPLab",L"2024-03-30");

    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager * pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDockManager, L"pMainWnd为空",L"GDMPLab",L"2024-03-30");
    IDock* pDock = pDockManager->GetDock(PickFilterDlg::GetDockName());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDock, L"pDock为空",L"GDMPLab",L"2024-03-30");
    IWidget* pWidget = pDock->GetWidget();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pWidget, L"pWidget为空",L"GDMPLab",L"2024-03-30");
    PickFilterDlg* pPickFilterDlg = dynamic_cast<PickFilterDlg*>(pWidget);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPickFilterDlg, L"pPickDlg为空",L"GDMPLab",L"2024-03-30");
    pPickFilterDlg->SetCurDoc(pDoc);//更新当前文档

    if (pDoc->IsFamilyDocument() == m_isFamilyDoc)//如果文件类型没有变化，则不需要刷新
        return;

    m_isFamilyDoc = pDoc->IsFamilyDocument();

    QTreeWidgetItem* topItem = pPickFilterDlg->m_ui.treeWidget->topLevelItem(0);
    int count = topItem->childCount();
    while (count >= 1)
    {
        QTreeWidgetItem* pItem = topItem->takeChild(0);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pItem, L"pItem为空",L"GDMPLab",L"2024-03-30");
        OwnerPtr<QTreeWidgetItem> opItem(pItem);        
        count--;
    }

    const IElementCanBePickedInModifyAction * IElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(IElementCanBePickedInModifyAction, L"IElementCanBePickedInModifyAction为空",L"GDMPLab",L"2024-03-30");
    const GbmpElementCanBePickedByCategoryInModifyAction* pElementCanBePickedByCategoryInModifyAction = dynamic_cast<const GbmpElementCanBePickedByCategoryInModifyAction*>(IElementCanBePickedInModifyAction);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementCanBePickedByCategoryInModifyAction, L"pElementCanBePickedByCategoryInModifyAction为空",L"GDMPLab",L"2024-03-30");
    std::set<UniIdentity> categoryIds = pElementCanBePickedByCategoryInModifyAction->GetCanNotBePickedCategories();

    FOR_EACH(curId, categoryIds)
    {
        const ICategory * pCurCategory = ICategoryLibrary::Get(pDoc)->GetCategory(curId);
        DBG_WARN_AND_CONTINUE_UNLESS(pCurCategory, L"获取到的ICategory指针为空，不合法",L"GDMPLab",L"2024-03-30");
        OwnerPtr<QTreeWidgetItem> curItem = NEW_AS_OWNER_PTR(QTreeWidgetItem, topItem);
        curItem->setCheckState(0, Qt::Checked);
        curItem->setText(0, QString::fromStdWString(GBMP_TR(pCurCategory->GetName())));
        topItem->addChild(TRANSFER_OWNERSHIP_TO_THIRD_PARTY(curItem));
    }
}

void PickFilterDlg::OnTreeItemClicked(QTreeWidgetItem* pItem, int index)
{
    IElementCanBePickedInModifyAction * IElementCanBePickedInModifyAction = IElementCanBePickedInModifyAction::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(IElementCanBePickedInModifyAction, L"IElementCanBePickedInModifyAction为空",L"GDMPLab",L"2024-03-30");
    GbmpElementCanBePickedByCategoryInModifyAction* pElementCanBePickedByCategoryInModifyAction = dynamic_cast<GbmpElementCanBePickedByCategoryInModifyAction*>(IElementCanBePickedInModifyAction);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementCanBePickedByCategoryInModifyAction, L"pElementCanBePickedByCategoryInModifyAction为空",L"GDMPLab",L"2024-03-30");

    bool hasChecked = false;
    bool hasUnChecked = false;
    if (m_ui.treeWidget->topLevelItem(0) == pItem)//点击“所有对象”,因为topLevel只有一个，所以直接用0
    {
        WhetherChildItemsAllChecked(pItem, hasChecked, hasUnChecked);

        if (!hasUnChecked)//如果子类全是选中状态，则改为全部未选中
        {
            pItem->setCheckState(index, Qt::CheckState::Unchecked);
            for (int i = 0; i < pItem->childCount(); i++)
            {
                pItem->child(i)->setCheckState(0, Qt::CheckState::Unchecked);
            }
            pElementCanBePickedByCategoryInModifyAction->ClearCategories(m_categoryIds);
        }
        else//否则为全选中
        {
            pItem->setCheckState(index, Qt::CheckState::Checked);
            for (int i = 0; i < pItem->childCount(); i++)
            {
                pItem->child(i)->setCheckState(0, Qt::CheckState::Checked);
            }
            pElementCanBePickedByCategoryInModifyAction->InitCategories(m_categoryIds);
        }
    }
    else//点击每个子项
    {
        UniIdentity categoryId = FindSelectedCategoryId(pItem, index);

        //如果勾选，则增加类别，如果未勾选，则取消类别
        if (categoryId.IsValid())
        {
            if (pItem->checkState(index) == Qt::CheckState::Checked)
            {
                pElementCanBePickedByCategoryInModifyAction->SetCanBePickedCategory(categoryId);
            }
            else if (pItem->checkState(index) == Qt::CheckState::Unchecked)
            {
                pElementCanBePickedByCategoryInModifyAction->SetCanNotBePickedCategory(categoryId);
            }
            else
            {
                DBG_WARN(L"错误的选择状态！",L"GDMPLab",L"2024-03-30");
            }
        }

        //根据子类的选择，确定header的选择状态
        WhetherChildItemsAllChecked(m_ui.treeWidget->topLevelItem(0), hasChecked, hasUnChecked);

        if (hasChecked && hasUnChecked)
        {
            m_ui.treeWidget->topLevelItem(0)->setCheckState(0, Qt::CheckState::PartiallyChecked);
        }
        else if (hasChecked == false)
        {
            m_ui.treeWidget->topLevelItem(0)->setCheckState(0, Qt::CheckState::Unchecked);
        }
        else if (hasUnChecked == false)
        {
            m_ui.treeWidget->topLevelItem(0)->setCheckState(0, Qt::CheckState::Checked);
        }
    }
}

gcmp::UniIdentity PickFilterDlg::FindSelectedCategoryId(QTreeWidgetItem* pItem, int index)
{
    UniIdentity categoryId = UniIdentity::InvalidUid;

    FOR_EACH(curId, m_categoryIds)
    {
        const ICategory * pCurCategory = ICategoryLibrary::Get(m_pDoc)->GetCategory(curId);
        DBG_WARN_AND_CONTINUE_UNLESS(pCurCategory, L"获取到的ICategory指针为空，不合法",L"GDMPLab",L"2024-03-30");
        if (pItem->text(index).toStdWString() == pCurCategory->GetName())
        {
            categoryId = pCurCategory->GetUniIdentity();
            break;
        }
    }
    return categoryId;
}

bool PickFilterDlg::WhetherChildItemsAllChecked(QTreeWidgetItem* pItem, bool& hasChecked, bool& hasUnChecked)
{
    hasChecked = false;
    hasUnChecked = false;
    for (int i = 0; i < pItem->childCount(); i++)
    {
        if (pItem->child(i)->checkState(0) == Qt::CheckState::Checked)
        {
            hasChecked = true;
        }
        else if (pItem->child(i)->checkState(0) == Qt::CheckState::Unchecked)
        {
            hasUnChecked = true;
        }
        else
        {
            DBG_WARN(L"错误的选择状态！",L"GDMPLab",L"2024-03-30");
        }
    }
    return true;
}

void PickFilterDlg::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Escape: //绕过QDialogESC键默认关闭对话框处理,同时保持消息路由
        event->ignore();
        QWidget::keyPressEvent(event);
        break;

    default:
        QDialog::keyPressEvent(event);
    }
}

gcmp::IDock * gcmp::PickFilterDlg::GetOwnerDock()
{
    IUiManager *pUiManager = IUiManager::Get();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUiManager, L"pUiManager为空",L"GDMPLab",L"2024-03-30");
    IDockManager * pDockManager = pUiManager->GetDockManager();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDockManager, L"pDockManager为空",L"GDMPLab",L"2024-03-30");
    return pDockManager->GetDock(PickFilterDlg::GetDockName());
}

void gcmp::PickFilterDlg::SetEnabled(bool bEnable)
{
    setEnabled(bEnable);
}
